﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace MSI2
{
    public class Program
    {
        public static int NumberOfAminoAcids = 21; //liczba aminokawsów - 20 + "pusty"
        public static int FirstLevelWindowSize = 13; //długość "okna":  13-21
        public static int SecondLevelWindowSize = 17;
        public static int AminoLength; //długość białka
        public static double Gamma = 0.5;
        public static double Beta = 0.1;
        public static int HiddenLayerSize = 6;
        public static int OutputLayerSize = 3;
        public static string InputFile = "fragment.txt";
        public static string FirstLayerFile = "firstLayerNetwork.dat";
        public static string SecondLayerFile = "secondLayerNetwork.dat";
        public static bool IsTraining = false;
        public static bool CreateNewNetwork = false;

        static void Main(string[] args)
        {
            if (!ReadParams(args))
            {
                Usage();
                return;
            }

            var parser = new Parser(InputFile);

            Console.WriteLine("---------------------------------------------------------------------");
            Console.WriteLine("Loading data from file " + InputFile + "...");
            Console.WriteLine("---------------------------------------------------------------------");
            
            var data = parser.LoadData();

            if (data == null)
                return;

            Console.WriteLine("---------------------------------------------------------------------");
            Console.WriteLine("Data loaded!");
            Console.WriteLine("---------------------------------------------------------------------");
            

            var first = new NeuralNetwork.NeuralNetworkParams
                            {
                                Beta = Beta,
                                Gamma = Gamma,
                                HiddenLayerSize = HiddenLayerSize,
                                InputLayerSize = NumberOfAminoAcids*FirstLevelWindowSize,
                                OutputLayerSize = OutputLayerSize
                            };

            var second = new NeuralNetwork.NeuralNetworkParams
                             {
                                 Beta = Beta,
                                 Gamma = Gamma,
                                 HiddenLayerSize = HiddenLayerSize,
                                 InputLayerSize = OutputLayerSize*SecondLevelWindowSize,
                                 OutputLayerSize = OutputLayerSize
                             };

            var phdSec = new PhdSec(first, second);
            
            if (!CreateNewNetwork)
            {
                phdSec.Load(FirstLayerFile, SecondLayerFile);
            }
            else
            {
                Console.WriteLine("---------------------------------------------------------------------");
                Console.WriteLine("New network created");
                Console.WriteLine("---------------------------------------------------------------------");
            }
            
            double avg = 0.0;
            int progress = -1;

            File.Delete(MainForm.outputFile);
            StreamWriter streamWriter = new StreamWriter(MainForm.outputFile, true);
            Console.WriteLine();

            Console.WriteLine("---------------------------------------------------------------------");
            Console.WriteLine("Progress:");

            int correctAns = 0, totalAns = 0; 

            for (int i = 0; i < data.Count; i++)
            {
                var current = (int)((double)i*100/data.Count);
                if (current > progress)
                {
                    progress = current;
                    Console.Write("\r" + progress + "%");
                }
                AminoLength = data[i].Sequence.Length / 21;
                var input = data[i].Sequence;
                var output = data[i].Structure;
                phdSec.Run(IsTraining, input, output, AminoLength);
                double score = phdSec.ComputeScore(data[i].Structure, ref correctAns, ref totalAns);
                phdSec.SaveOutput(data[i], streamWriter);
               // if (score >= 100 || Double.IsNaN(score) || Double.IsPositiveInfinity(score)) continue;
                avg += score;
            }
            Console.WriteLine();
            Console.WriteLine("---------------------------------------------------------------------");

            streamWriter.Close();

            

            Console.WriteLine();
            Console.WriteLine("---------------------------------------------------------------------");
            Console.WriteLine("Total score: " + (double)100*correctAns/totalAns);
            Console.WriteLine("---------------------------------------------------------------------");
            Console.WriteLine("---------------------------------------------------------------------");
            Console.WriteLine("Average score: " + (avg / data.Count));
            Console.WriteLine("---------------------------------------------------------------------");


            if (IsTraining)
                phdSec.Save(FirstLayerFile, SecondLayerFile);
        }

        private static void Usage()
        {
            Console.WriteLine("Wrong params!");
            Console.WriteLine("Usage:");
            Console.WriteLine("[-training] - runs application in Training Mode, otherwise Training Mode is inactive");
            Console.WriteLine("[-input InputFileName] - specifies input data file, otherwise default input file used:" + InputFile);
            Console.WriteLine("[-newNetwork | -networks FirstLevelFileName SecondLevelFileName] - creates new network or uses specified files");
        }

        private static bool ReadParams(IEnumerable<string> args)
        {
            var argsList = args.ToList();

            IsTraining = argsList.Contains("-training");

            if (argsList.Contains("-input"))
            {
                int index = argsList.IndexOf("-input");
                InputFile = argsList[index + 1];
            }
            
            CreateNewNetwork = argsList.Contains("-newNetwork");

            if (argsList.Contains("-networks"))
            {
                if (CreateNewNetwork)
                {
                    return false;
                }

                int index = argsList.IndexOf("-input");

                FirstLayerFile = argsList[index + 1];
                SecondLayerFile = argsList[index + 2];
            }

            return true;
        }
    }
}
